﻿using System;
using System.Linq;

namespace DotNetCommon.Extensions
{
    /// <summary>
    /// 数组扩展类
    /// </summary>
    public static class ArrayExtensions
    {
        #region 循环操作 Next/Pre/ReverseFluent/ReSetStart
        /// <summary>
        /// 循环操作场景(一个多边形的点位遍历), 返回指定索引的下一个元素,如:
        /// <code>
        /// new Vector2[] { new(0, 0), new(1, 0), new(1, 1) }.Next(2).ShouldBe(new(0, 0));
        /// </code>
        /// </summary>
        public static T Next<T>(this T[] arr, int index)
        {
            return arr[(index + 1) % arr.Length];
        }
        /// <summary>
        /// 循环操作场景(一个多边形的点位遍历),返回指定索引的上一个元素,如:
        /// <code>
        /// new Vector2[] { new(0, 0), new(1, 0), new(1, 1) }.Pre(0).ShouldBe(new(1, 1));
        /// </code>
        /// </summary>
        public static T Pre<T>(this T[] arr, int index)
        {
            return arr[(index - 1 + arr.Length) % arr.Length];
        }
        /// <summary>
        /// 将自身翻转, 并返回自身,如下:
        /// <code>
        /// new int[] { 1, 2, 3, 4 }.ReverseFluent().ShouldBe(new int[] { 4, 3, 2, 1 });
        /// </code>
        /// </summary>
        public static T[] ReverseFluent<T>(this T[] arr)
        {
            for (int i = 0; i < arr.Length / 2; i++)
            {
                (arr[i], arr[arr.Length - i - 1]) = (arr[arr.Length - i - 1], arr[i]);
            }
            return arr;
        }
        /// <summary>
        /// 旋转集合, 使 <c>index</c> 位置的元素作为新的起始元素, 返回新的集合, 如下:
        /// <code>
        /// new int[] { 1, 2, 3, 4 }.ReSetStart(2).ShouldBe(new int[] { 3, 4, 1, 2 });
        /// new int[] { 1, 2, 3, 4 }.ReSetStart(-1).ShouldBe(new int[] { 4, 1, 2, 3 });
        /// </code>
        /// </summary>
        public static T[] ReSetStart<T>(this T[] arr, int index, bool reverse = false)
        {
            index %= arr.Length;
            if (index < 0) index += arr.Length;
            if (reverse)
            {
                return arr.Take(index + 1).Reverse().Concat(arr.Skip(index + 1).Take(arr.Length - index - 1).Reverse()).ToArray();
            }
            else
            {
                return arr.Skip(index).Take(arr.Length - index).Concat(arr.Take(index)).ToArray();
            }
        }
        #endregion

        #region Fluent风格 T[] SetFluent
        /// <summary>
        /// Fluent风格: 设置数组中指定索引的值
        /// </summary>
        /// <remarks>
        /// 注意:
        /// <list type="bullet">
        /// <item>如果数组为null或索引超出,抛出异常</item>
        /// </list>
        /// </remarks>
        public static T[] SetFluent<T>(this T[] arr, int index, T b)
        {
            arr[index] = b;
            return arr;
        }

        /// <summary>
        /// Fluent风格: 设置数组中指定索引的值
        /// </summary>
        /// <remarks>
        /// 注意:
        /// <list type="bullet">
        /// <item>如果数组为null或索引超出,抛出异常</item>
        /// </list>
        /// </remarks>
        public static T[] SetFluent<T>(this T[] arr, int index, Func<T, T> func)
        {
            if (func == null) return arr;
            arr[index] = func(arr[index]);
            return arr;
        }

        /// <summary>
        /// Fluent风格: 批量设置数组中的值
        /// </summary>
        /// <remarks>
        /// 注意:
        /// <list type="bullet">
        /// <item>如果数组为null或索引超出,抛出异常</item>
        /// </list>
        /// </remarks>
        public static T[] SetFluent<T>(this T[] arr, Func<T, bool> filter, Func<T, T> func)
        {
            if (func == null) return arr;
            for (int i = 0; i < arr.Length; i++)
            {
                var b = filter?.Invoke(arr[i]);
                if (b == false) continue;
                arr[i] = func(arr[i]);
            }
            return arr;
        }
        #endregion

        #region FindIndex FindLastIndex
        /// <summary>
        /// 类似 list.FindIndex
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="arr"></param>
        /// <param name="match"></param>
        /// <returns></returns>
        public static int FindIndex<T>(this T[] arr, Predicate<T> match)
        {
            for (int i = 0; i < arr.Length; i++)
            {
                if (match(arr[i])) return i;
            }
            return -1;
        }
        /// <summary>
        /// 类似 list.FindLastIndex
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="arr"></param>
        /// <param name="match"></param>
        /// <returns></returns>
        public static int FindLastIndex<T>(this T[] arr, Predicate<T> match)
        {
            for (int i = arr.Length - 1; i >= 0; i--)
            {
                if (match(arr[i])) return i;
            }
            return -1;
        }
        #endregion
    }
}
